﻿using System.Diagnostics;
using Co9320.NamaAlert.Engine.Feeder;
using Co9320.NamaAlert.Engine.Lists;
using System;

namespace Co9320.NamaAlert.Engine.Inspector
{
	/// <summary>
	/// オンエア検知クラス
	/// </summary>
	/// <remarks>
	/// 基本的に､ある時点において､このインスタンスの中に存在スレッドは単一である
	/// との仮定に基づいた設計｡
	/// 複数のスレッドが同一のタイミングでインスタンス中に存在する場合の結果は未定義｡
	/// また､終了検知系と同時実行した場合の結果も未定義｡
	/// </remarks>
	internal class OnAirListBuilder
	{
		/// <summary>
		/// Rssフィーダエンジン
		/// </summary>
		private NicoLiveLiveInfoFeeder Feeder_;

		/// <summary>
		/// 放送情報保持用リスト
		/// </summary>
		private InternalLiveList PresetList_;

		/// <summary>
		/// イニシャライズ指定フラグ
		/// </summary>
		private bool ReInitialyze_;

		/// <summary>
		/// 初回クロールが終了したときに発生するイベント
		/// </summary>
		public event EventHandler FirstCrawlingComplted;

		/// <summary>
		/// Ctor
		/// </summary>
		/// <param name="LookAhead">閾超えた後にどれだけ先を見に行くか</param>
		/// <param name="Threashold">読み込み打ち切りの閾値</param>
		/// <param name="List">放送情報保持用リスト</param>
		/// <param name="Counter">フィードカウンタ</param>
		/// <param name="BaseUri">Rss見に行くときに使うフォーマットベースURI</param>
		/// <param name="UserAgent">ユーザーエージェント</param>
		public OnAirListBuilder(int LookAhead, double Threashold, InternalLiveList List,
			NicoLiveLiveInfoFeeder feeder)
		{
			Debug.Assert(LookAhead >= 0);
			Debug.Assert(Threashold > 0);
			Debug.Assert(List != null);
			Debug.Assert(feeder != null);

			Feeder_ = feeder;
			this.Threashold = Threashold;
			this.LookAhead = LookAhead;
			this.PresetList_ = List;
			ReInitialyze_ = true;
		}

		/// <summary>
		/// ルーチンメソッド
		/// </summary>
		/// <returns>保持している放送数</returns>
		public int RoutineWork()
		{
			return RoutineWork(PresetList_);
		}

		/// <summary>
		/// ルーチンメソッド
		/// プリセットリスト使わないタイプ｡
		/// </summary>
		/// <param name="List">取得情報を保持しておくリスト</param>
		/// <returns>保持している放送数</returns>
		public int RoutineWork(InternalLiveList List)
		{
			Debug.Assert(List != null);


			Feeder_.ResetPage();

			if (ReInitialyze_)
			{

				for (; ; )
				{
					var lst = Feeder_.ReadPage();

					if (lst.Count == 0)
					{
						break;
					}
					else
					{
						List.Inspect(lst);
					}
                    System.Threading.Thread.Sleep(10);
				}



				OnFirstCrawlingComplted(this, EventArgs.Empty);
				ReInitialyze_ = false;
			}
			else
			{
				NormalRoutine(List);
			}

			return Feeder_.CurrentProgramCount;
		}

		/// <summary>
		/// イニシャル時以外の内部ルーチン
		/// </summary>
		/// <param name="List">保持リスト</param>
		private void NormalRoutine(InternalLiveList List)
		{
			Debug.Assert(List != null);



			for (int i = 0; ; i++)
			{
				FeedingLivePrograms lst = Feeder_.ReadPage();

				if (lst.Count == 0)
				{
					break;
				}

				double ratio = List.Inspect(lst);

				if (ratio > Threashold && i != 0)
				{
					if (Overlap(List))
					{
						continue;
					}
					else
					{
						break;
					}
				}
				else
				{
					continue;
				}
			}

		}

		/// <summary>
		/// LookAheadの処理
		/// </summary>
		/// <param name="List">保持リスト</param>
		/// <returns>先読みした結果閾を超えたか超えなかったか</returns>
		private bool Overlap(InternalLiveList List)
		{
			bool Ret = false;

			for (int i = 0; i < LookAhead; i++)
			{
				var lst = Feeder_.ReadPage();

				if (lst.Count == 0)
				{
					Ret = false;
					break;
				}
				else
				{
					if (List.Inspect(lst) > Threashold)
					{
						continue;
					}
					else
					{
						Ret = true;
						break;
					}
				}
			}


			return Ret;
		}

		private void OnFirstCrawlingComplted(object sender, EventArgs e)
		{
			if (this.FirstCrawlingComplted != null)
			{
				FirstCrawlingComplted(sender, e);
			}
		}

		public void RequestReInitialize()
		{
			this.ReInitialyze_ = true;
		}

		public void RepressionReInitialize()
		{
			this.ReInitialyze_ = false;
		}


		public int LookAhead
		{
			get;
			private set;
		}

		public double Threashold
		{
			get;
			private set;
		}
	}
}
